﻿using System;
using System.Linq;
using System.Transactions;
using Extreme.SPFramework.DependencyInjection;
using Extreme.SPFramework.DomainModel;
using Extreme.SPFramework.Test.Entities;
using Extreme.SPFramework.Test.Interfaces;
using NUnit.Framework;

namespace Extreme.SPFramework.Test.Linq
{
    [TestFixture]
    public class LinqTestFixture
    {
        [Test]
        public void TestDataContext()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                insurerRepository.SaveItem(new Insurer() {Name = "First"});

                var context = new DbTestDataContext();

                var allItems = context.Insurers.Where(item => item.Name == "First");
                allItems = allItems.OrderBy(item => item.Name);
                Assert.GreaterOrEqual(allItems.Count(), 1);
            }
        }

        [Test]
        public void TestGetAll()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                insurerRepository.SaveItem(new Insurer() {Name = "First"});
                var allItems = insurerRepository.GetAllItems();

                Assert.IsNotEmpty(allItems);
                Assert.IsTrue(allItems.Exists(item => item.Name == "First"));
            }
        }

        [Test]
        public void TestExpressionQuery()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var insurer = new Insurer() {Name = "Insurer name"};
                insurerRepository.SaveItem(insurer);

                var caseRepository = ServiceProvider.GetInstance<ICaseRepository>();
                caseRepository.SaveItem(new Case(){ Name = "ABC", Insurer = insurer, Status = "STATUS"});
                var foundItems = caseRepository.SearchByCriteria(new CaseSearchCriteria(){ CaseName = "ABC"});
                Assert.IsNotEmpty(foundItems);
            }
        }

        [Test]
        public void TestInsertItem()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var newItem = new Insurer() {Name = Guid.NewGuid().ToString()};
                insurerRepository.SaveItem(newItem);

                var dbItem = insurerRepository.GetItem(newItem.Id);

                Assert.AreEqual(newItem.Id, dbItem.Id);
                Assert.AreEqual(newItem.Name, dbItem.Name);
            }
        }

        [Test]
        public void TestUpdateItem()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var newItem = new Insurer() { Name = Guid.NewGuid().ToString() };
                insurerRepository.SaveItem(newItem);
                var dbItem = insurerRepository.GetItem(newItem.Id);

                dbItem.Name = Guid.NewGuid().ToString();
                insurerRepository.SaveItem(dbItem);
                var modifiedItem = insurerRepository.GetItem(dbItem.Id);

                Assert.AreEqual(dbItem.Name, modifiedItem.Name);
            }
        }

        [Test]
        public void TestDeleteItem()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var newItem = new Insurer() { Name = Guid.NewGuid().ToString() };
                insurerRepository.SaveItem(newItem);
                var dbItem = insurerRepository.GetItem(newItem.Id);

                insurerRepository.DeleteItem(dbItem.Id);

                Assert.IsEmpty(insurerRepository.GetAllItems().Where(item => item.Id == dbItem.Id).ToList());
            }
        }

        [Test]
        public void TestUpdateItemWithCollection1()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var newItem = new Insurer() { Name = Guid.NewGuid().ToString() };
                insurerRepository.SaveItem(newItem);

                var dbItem = insurerRepository.GetItem(newItem.Id);
                dbItem.Name = Guid.NewGuid().ToString();
                dbItem.Cases.Add(new Case(){Name = "New case", Status = "New"});               
                insurerRepository.SaveItem(dbItem);

                dbItem = insurerRepository.GetItem(newItem.Id);
                Assert.AreEqual(1, dbItem.Cases.Count);
                dbItem.Cases[0].Name = "New name";
                dbItem.Cases.Add(new Case() { Name = "New case 2", Status = "New 2" });
                insurerRepository.SaveItem(dbItem);

                var modifiedItem = insurerRepository.GetItem(dbItem.Id);
                Assert.AreEqual(dbItem.Name, modifiedItem.Name);
                Assert.AreEqual(2, modifiedItem.Cases.Count);
                Assert.IsNotEmpty(modifiedItem.Cases.Where(c => c.Name == "New name").ToList());
            }
        }

        [Test]
        public void TestUpdateItemWithCollection2()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var newItem = new Insurer() { Name = Guid.NewGuid().ToString() };

                var case1 = new Case() {Name = "FirstCase", Status = "New1"};
                var case2 = new Case() { Name = "SecondCase", Status = "New2" };
                var case3 = new Case() { Name = "ThirdCase", Status = "New3" };

                newItem.Cases.Add(case1);
                newItem.Cases.Add(case2);

                insurerRepository.SaveItem(newItem);
                var dbItem = insurerRepository.GetItem(newItem.Id);
                Assert.AreEqual(2, dbItem.Cases.Count);

                dbItem.Cases.Where(item => item.Name == case1.Name).First().Name = "FirstCase_Update";
                dbItem.Cases.Add(case3);
                insurerRepository.SaveItem(dbItem);

                var dbItem2 = insurerRepository.GetItem(newItem.Id);
                Assert.AreEqual(3, dbItem2.Cases.Count);
                Assert.IsTrue(dbItem2.Cases.Where(item => item.Name == "FirstCase_Update" && item.Id == case1.Id).Count() == 1);
            }
        }

        [Test]
        public void TestUpdateWithDeleteCollectionItem()
        {
            using (var scope = new TransactionScope())
            {
                var insurerRepository = ServiceProvider.GetInstance<IRepository<Insurer>>();
                var newItem = new Insurer() { Name = Guid.NewGuid().ToString() };

                var case1 = new Case() { Name = "FirstCase", Status = "New1" };
                var case2 = new Case() { Name = "SecondCase", Status = "New2" };

                newItem.Cases.Add(case1);
                newItem.Cases.Add(case2);

                insurerRepository.SaveItem(newItem);
                var dbItem = insurerRepository.GetItem(newItem.Id);

                dbItem.Cases.RemoveAt(0);
                insurerRepository.SaveItem(dbItem);

                var dbItem2 = insurerRepository.GetItem(newItem.Id);
                Assert.AreEqual(1, dbItem2.Cases.Count);
            }
        }
    }
}
